package dao

import (
	"haiqiu-go-admin/entity"
	"haiqiu-go-admin/entity/dto"
	"haiqiu-go-admin/utils"
	"log"
	"strconv"
)

type LogDao struct {
}

func StatisticsLog() (any, error) {
	rows, err := DB.Query("SELECT request_address AS address, count(request_address) AS quantity FROM sys_log " +
		"where 1=1 and create_time > DATE_SUB(CURDATE(), INTERVAL 3 MONTH) " +
		"GROUP BY request_address ORDER BY count(request_address) desc LIMIT 10")
	if err != nil {
		panic(err)
	}
	// 数据列
	columns, err := rows.Columns()
	if err != nil {
		log.Println(err)
		return nil, err
	}

	// 列的个数
	count := len(columns)

	// 返回值 Map切片
	mData := make([]map[string]interface{}, 0)
	// 一条数据的各列的值（需要指定长度为列的个数，以便获取地址）
	values := make([]interface{}, count)
	// 一条数据的各列的值的地址
	valPointers := make([]interface{}, count)
	for rows.Next() {

		// 获取各列的值的地址
		for i := 0; i < count; i++ {
			valPointers[i] = &values[i]
		}

		// 获取各列的值，放到对应的地址中
		rows.Scan(valPointers...)

		// 一条数据的Map (列名和值的键值对)
		entry := make(map[string]interface{})

		// Map 赋值
		for i, col := range columns {
			var v interface{}

			// 值复制给val(所以Scan时指定的地址可重复使用)
			val := values[i]
			b, ok := val.([]byte)
			if ok {
				// 字符切片转为字符串
				v = string(b)
			} else {
				v = val
			}
			entry[col] = v
		}

		mData = append(mData, entry)
	}

	return mData, nil
}

// 分页查询总条数
func (LogDao) LogPageCount(page dto.LogQueryDto) (count int64) {
	wrapper := utils.QueryWrapper().Count("sys_log")
	LogDao{}.getLogCondition(&page, wrapper)
	err := DB.QueryRow(wrapper.GetSql(), wrapper.GetVal()...).Scan(&count)
	if err != nil {
		log.Println(err.Error())
	}
	return count
}

// 分页查询数据
func (LogDao) LogPageList(page dto.LogQueryDto) (*[]entity.SysLog, error) {
	wrapper := utils.QueryWrapper().Page("sys_log", page.PageIndex, page.PageSize).
		OrderByDesc("create_time")
	LogDao{}.getLogCondition(&page, wrapper)
	rows, err := DB.Query(wrapper.GetSql(), wrapper.GetVal()...)
	if err != nil {
		log.Println(err.Error())
		return nil, err
	}
	var sysLogs []entity.SysLog
	for rows.Next() {
		var sysLog = entity.SysLog{}
		err := rows.Scan(
			&sysLog.Id,
			&sysLog.Operation,
			&sysLog.RequestParam,
			&sysLog.ResponseJson,
			&sysLog.RequestIp,
			&sysLog.RequestAddress,
			&sysLog.Username,
			&sysLog.RestUrl,
			&sysLog.Result,
			&sysLog.Os,
			&sysLog.Method,
			&sysLog.Browser,
			&sysLog.CreateTime,
			&sysLog.UpdateTime,
		)
		if err != nil {
			log.Println(err.Error())
			return nil, err
		}
		sysLogs = append(sysLogs, sysLog)
	}
	return &sysLogs, nil
}

func (LogDao) getLogCondition(page *dto.LogQueryDto, wrapper *utils.Wrapper) {
	if page.Params.Username != nil {
		wrapper.Eq("username", *page.Params.Username)
	}
	if page.Params.RequestAddress != nil {
		wrapper.Like("request_address", *page.Params.RequestAddress)
	}
	if page.Params.Result != nil {
		wrapper.Eq("result", *page.Params.Result)
	}
	if page.Params.Method != nil {
		wrapper.Eq("method", *page.Params.Method)
	}
	if page.Params.Operation != nil {
		wrapper.Eq("operation", *page.Params.Operation)
	}
	if page.Params.BeginTime != nil && page.Params.EndTime != nil {
		wrapper.Between("create_time", *page.Params.BeginTime,
			*page.Params.EndTime)
	}
}

func (LogDao) LogById(id int64) (*entity.SysLog, error) {
	wrapper := utils.QueryWrapper().GetById("sys_log", id)
	stmt, err := DB.Prepare(wrapper.GetSql())
	if err != nil {
		panic(err)
	}
	row := stmt.QueryRow(wrapper.GetVal())
	var sysLog entity.SysLog
	err = row.Scan(
		&sysLog.Id,
		&sysLog.Operation,
		&sysLog.RequestParam,
		&sysLog.ResponseJson,
		&sysLog.RequestIp,
		&sysLog.RequestAddress,
		&sysLog.Username,
		&sysLog.RestUrl,
		&sysLog.Result,
		&sysLog.Os,
		&sysLog.Method,
		&sysLog.Browser,
		&sysLog.CreateTime,
		&sysLog.UpdateTime,
	)
	if err != nil {
		panic(err)
	}
	return &sysLog, nil
}

// LogAdd 新增数据
func (LogDao) LogAdd(sysLog *entity.SysLog) (int64, error) {
	exec, err := DB.Exec("insert into `sys_log` (`id`, `operation`, `request_param`, "+
		"`response_json`, `request_ip`, `request_address`, `username`, `rest_url`, "+
		"`result`, `os`, `method`, `browser`, `create_time`, `update_time` ) "+
		"values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )",
		&sysLog.Id,
		&sysLog.Operation,
		&sysLog.RequestParam,
		&sysLog.ResponseJson,
		&sysLog.RequestIp,
		&sysLog.RequestAddress,
		&sysLog.Username,
		&sysLog.RestUrl,
		&sysLog.Result,
		&sysLog.Os,
		&sysLog.Method,
		&sysLog.Browser,
		&sysLog.CreateTime,
		&sysLog.UpdateTime,
	)
	if err != nil {
		return 0, err
	}
	rowsAffected, err := exec.RowsAffected()
	if err != nil {
		return 0, err
	}
	return rowsAffected, nil
}

// LogUpdate 根据ID更新数据
func (LogDao) LogUpdate(sysLog *entity.SysLog) (int64, error) {
	exec, err := DB.Exec("update `sys_log` set `operation` = ?, "+
		"`request_param` = ?, `response_json` = ?, `request_ip` = ?, `request_address` = ?, "+
		"`username` = ?, `rest_url` = ?, `result` = ?, `os` = ?, `method` = ?, "+
		"`browser` = ?, `create_time` = ?, `update_time` = ? where `id` = ?",
		&sysLog.Operation,
		&sysLog.RequestParam,
		&sysLog.ResponseJson,
		&sysLog.RequestIp,
		&sysLog.RequestAddress,
		&sysLog.Username,
		&sysLog.RestUrl,
		&sysLog.Result,
		&sysLog.Os,
		&sysLog.Method,
		&sysLog.Browser,
		&sysLog.CreateTime,
		&sysLog.UpdateTime,
		&sysLog.Id,
	)
	if err != nil {
		return 0, err
	}
	rowsAffected, err := exec.RowsAffected()
	if err != nil {
		return 0, err
	}
	return rowsAffected, nil
}

// LogDelete 根据ID删除数据
func (LogDao) LogDelete(id int64) (int64, error) {
	exec, err := DB.Exec("delete from sys_log where id = ?")
	if err != nil {
		panic(err)
		return 0, err
	}
	rowsAffected, err := exec.RowsAffected()
	if err != nil {
		panic(err)
		return 0, err
	}
	return rowsAffected, nil
}

// LogDeleteBatch 根据ID批量删除数据
func (LogDao) LogDeleteBatch(ids []int64) (int64, error) {
	var idsStr string
	for index, id := range ids {
		if index == len(ids)-1 {
			idsStr += strconv.FormatInt(id, 10)
		} else {
			idsStr += strconv.FormatInt(id, 10) + ", "
		}
	}
	exec, err := DB.Exec("delete from sys_dept where id in (?)", idsStr)
	if err != nil {
		panic(err)
		return 0, err
	}
	rowsAffected, err := exec.RowsAffected()
	if err != nil {
		panic(err)
		return 0, err
	}
	return rowsAffected, nil
}
